# -*- coding: utf-8 -*-
# standard
import os
import sys
import json

# third
import requests
from cachelib import SimpleCache

# local
_P_PATH =  os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if _P_PATH not in sys.path:
    sys.path.append(_P_PATH)
from models.message_model import *


"""
@Title:  Push到消息中心 
@File: push_model.py
@Author: walle 2025年01日06日 15时47分23秒
@Version: 1.0.0
@Desc: 
"""


MESSAGE_CENTER_URL = "http://61.169.129.195:19001"
TOKEN_CACHE = SimpleCache()  # token缓存
TOKEN_CACHE_KEY = "message_center_token"  # token缓存key
TOKEN_TTL = 7 * 24 * 3600 - 15  # token缓存时间


class TokenExpired(Exception):
    def __init__(self, message: str = "token 过期"):
        self.message = message
        super().__init__(self.message)



class MessageCenterTokenOrm(Base, OrmTools):
    __tablename__ = 'message_center_token'
    __table_args__ = {
        'comment': '消息中心token表'
    }
    id = Column(Integer, primary_key=True, autoincrement=True, comment='主键')
    token = Column(String(512), nullable=True, comment='token')
    is_deleted = Column(Integer, nullable=True, default=0, comment="是否已作废")
    expire_time = Column(DateTime, nullable=True, default=None, comment='过期时间')
    error = Column(String(512), nullable=True, default=None, comment='错误信息')
    create_time = Column(DateTime, default=datetime.now, comment='创建时间')

    @classmethod
    def login_message_center(cls):
        """
        登录消息中心
        """
        url = f"{MESSAGE_CENTER_URL}/login"
        data = {
            "username": "yuhe",
            "password": "6f8db47c39e8a7c95dfc8a43fce99b9f"  # yhjk&1205  16位哈希值
        }
        now = datetime.now()
        resp = common_send_request(method="post", timeout=15,
                                   url=url, json=data, repackage_response=False)
        if resp:
            expire_time = now + timedelta(seconds=TOKEN_TTL)
            resp.data = {
                "token": resp.data["access_token"],
                "expire_time": expire_time,
                'create_time': now
            }
        else:
            resp.data = {
                "error": resp.error,
                'create_time': now
            }
            logger.error(f"登录消息中心失败, {resp.error}")
        return resp

    # @classmethod
    # def format_group_content(cls, customer_name: str, 
    #                          store_name: str, 
    #                          alert_time: datetime,
    #                          raw_content, method: str) -> str:
    #     """
    #     格式化内容以符合推送群消息的要求
    #     """
    #     if method == NotificationMethodName.WORK_WX_GROUP.value:
    #         return raw_content
    #     else:
    #         raw_content = f"{customer_name}的{store_name}于{alert_time.strftime('%Y-%m-%d %H:%M:%S')} {raw_content}"
    #         if method == NotificationMethodName.DD_GROUP.value:
    #             return f"警告： {raw_content}"
    #         else:
    #             return raw_content
    
    @classmethod
    def _get_token(cls) -> Resp:
        """
        从数据库获取最新token，如果没有就从远程服务端重新获取一个
        """
        db_session, resp = new_db_session(sync=True), Resp()
        s = select(
            cls,
        ).where(
            cls.is_deleted == 0,
            cls.expire_time > datetime.now()
        )
        one = db_session.scalar(s)
        if one:
            resp.data = {
                "token": one.token,
                "expire_time": one.expire_time
            }
        else:
            resp = cls.login_message_center()
            one = cls(**resp.data)
            db_session.add(one)
            db_session.commit()
            if resp:
                resp.data = {
                    "token": one.token,
                    "expire_time": one.expire_time
                }
            else:
                pass
        db_session.close()
        return resp 
    
    @classmethod
    def _delete_token(cls) -> None:
        """
        标记数据库中的token过期
        """
        db_session = new_db_session(sync=True)
        s = update(
            cls,
        ).where(
            cls.is_deleted == 0,
            cls.expire_time > datetime.now()
        ).values(is_deleted=1)
        result = db_session.execute(s)
        db_session.commit()
        db_session.close()
        logger.debug(f"删除了{result.rowcount}个token")
    
    @classmethod
    def get_token_from_cache(cls) -> Resp:
        """
        从缓存获取token
        resp.data = token
        """
        resp = Resp()
        need_refresh = True  # 是否需要刷新token
        result = TOKEN_CACHE.get(key=TOKEN_CACHE_KEY)
        if result:
            if result['expire_time'] > datetime.now():
                resp.data = result['token']
                need_refresh = False
            else:
                need_refresh = True
        if need_refresh:
            resp = cls._get_token()
            if resp:
                result = resp.data
                expire_time: datetime = resp.data['expire_time']
                timeout = (expire_time - datetime.now()).total_seconds()
                TOKEN_CACHE.set(key=TOKEN_CACHE_KEY, value=result, timeout=timeout)
                resp.data = result['token']
        return resp
    
    @classmethod
    def clear_token(cls):
        """
        清除缓存中的token并标记数据库中对应的记录为过期
        """
        TOKEN_CACHE.delete(key=TOKEN_CACHE_KEY)
        cls._delete_token()

    @classmethod
    def get_url(cls, method: str) -> Resp:
        """
        获取url
        :param method: _description_
        :return: _description_
        """
        resp = Resp()
        path = None
        if method == NotificationMethodName.DD_GROUP.value:
            path = "/robot_send/dingding"
        elif method == NotificationMethodName.WORK_WX_GROUP.value:
            path = "/robot_send/qiyeweixin"
        elif method == NotificationMethodName.FEISHU.value:
            path = "/robot_send/feishu"
        elif method == NotificationMethodName.SMS.value:
            path = "/message_send/aliyun"   
        elif method == NotificationMethodName.TEL.value:
            path = "/voice_send/aliyun"   
        else:
            resp.message = f"未实现的推送方式: {method}"
            logger.warning(resp.message)
        if resp:
            resp.data = f"{MESSAGE_CENTER_URL}{path}"
        return resp
    
    @classmethod
    def send_sms_message(cls, targets: List[str], store_name: str, 
                          url: str, headers: dict,
                          alert_time: datetime, message: str) -> dict:
        """
        发送短信
        return {
        id: resp.message  # success 表示成功
        }
        """
        result = {}
        for phone in targets:
            kw = {
                "iphone": phone,
                "template_param": {
                    "store_name": store_name,
                    "time": alert_time.strftime("%y-%m-%d %H:%M:%S"),
                    "type": message
                }
            }
            resp = common_send_request(method='post',
                                       url=url, json=kw, 
                                       headers=headers, 
                                       repackage_response=False)
            if not resp:
                if "expired" in resp.message:
                    raise TokenExpired()
                result[phone] = resp.message
            elif resp.data['Code'] != "OK":
                result[phone] = resp.data['Message']
            else:
                result[phone] = "success"
        return result
    
    @classmethod
    def send_tel_voice(cls, targets: List[str], store_name: str, 
                          url: str, headers: dict,
                          alert_time: datetime, message: str) -> dict:
        """
        发送语音
        return {
        id: resp.message  # success 表示成功
        }
        """
        result = {}
        for phone in targets:
            kw = {
                "called_number": phone,
                "store": store_name,
                "event": f'{message} {alert_time.strftime("%y-%m-%d %H:%M:%S")}',
            }
            resp = common_send_request(method='post',
                                       url=url, json=kw, 
                                       headers=headers, 
                                       repackage_response=False)
            if not resp: # 函数抛出异常
                if "expired" in resp.message:
                    raise TokenExpired()
                result[phone] = resp.message
            elif resp.data['errmsg'] != "ok":  # 发送出错
                result[phone] = resp.data['errmsg']
            else:
                if message := resp.data.get("message"):  # 内容违规的情况
                    result[phone] = message
                else:
                    result[phone] = "success"
        return result

    @classmethod
    def demo_send(cls, content: str):
        """
        这是原始的发送方法 放在这里做验证
        :param content: _description_
        """
        if not content:
            content = "## 服务器监控告警\n**时间**: 2023-11-01 14:30  \n**主机**: 192.168.1.100  \n**状态**: <font color=\"#0000FF\">CPU使用率95%</font>  \n\n### 详细信息\n- 当前负载: `4.8`\n- 阈值: `>80%` 持续5分钟\n- [点击查看详情](http://monitor.example.com)"
        url = "http://61.169.129.195:19001/robot_send/dingding"

        payload = json.dumps({
            "key": "785d7dcf97a7a7caf4684f43a6215402b618fb4fbd4fd3aeca68ea9ac294de32",
            "type": "markdown",
            "content": content
        }).encode('utf-8')

        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc1MjIyMDE4MiwianRpIjoiYzNkMGM1OWYtMTg5NC00OTk4LWExZjMtN2U3ZjA5NjIxMGU2IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6IjEiLCJuYmYiOjE3NTIyMjAxODIsImNzcmYiOiI3MGYzYjdhZC00Zjk1LTRkZmUtYmVjOS1lMjMwYjRhNmMyYTAiLCJleHAiOjE3NTI4MjQ5ODJ9.UiT6AuACvkbO9r7FeAO54l2bIxYrMV90PeN5cuSWIfY'
        }

        response = requests.request("POST", url, headers=headers, data=payload)

        print(response.text)
            
    @classmethod
    def _send_messages(cls, method: str, content: str, targets: List[str], 
                     store_name: str, alert_time: datetime, source: str,
                     customer_name: str, **kwargs) -> Resp:
        """
        发送消息
        """
        resp = cls.get_token_from_cache()
        if not resp:
            return resp
        token = resp.data  # 获取token
        resp = cls.get_url(method)
        if not resp:
            return resp
        url = resp.data  # 获取url
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        if method == NotificationMethodName.SMS.value:
            result = cls.send_sms_message(targets=targets, 
                                  store_name=store_name, 
                                  url=url, headers=headers, 
                                  alert_time=alert_time, 
                                  message=content)
        elif method == NotificationMethodName.TEL.value:
            result = cls.send_tel_voice(targets=targets, 
                                  store_name=store_name, 
                                  url=url, headers=headers, 
                                  alert_time=alert_time, 
                                  message=content)
        else:  # 发送dd群，企业微信和飞书
            result = {}
            for key in targets:
                kw = {
                    "key": key,
                    "type": "markdown",
                    "content": content,
                }
                resp = common_send_request(method='post',
                                       url=url, json=kw, 
                                       headers=headers, 
                                       repackage_response=False)
                logger.debug(f"content: {content}")
                if not resp:
                    if "expired" in resp.message:
                        raise TokenExpired()
                    result[key] = resp.message
                elif resp.data['errcode'] != 0:
                    result[key] = resp.data['errmsg']
                else:
                    result[key] = "success"
        resp.data = result
        return resp
    
    @classmethod
    def send_messages(cls, method: str, content: str, targets: List[str], 
                     store_name: str, alert_time: datetime, source: MicServiceSource,
                     customer_name: str, retry: bool = False, **kwargs) -> Resp:
        """
        发送消息
        :param method:   通知方式
        :param content:  通知内容
        :param targets:  目标
        :param store_name: 门店名称
        :param alert_time: 通知时间
        :param source:  来源 MicServiceSource 的实例
        :param customer_name: 客户名称
        :param retry:  是否重试
        """
        resp = Resp()
        content = content.replace("\\n", "\n")
        kw = dict(method=method,
                  content=content,
                  targets=targets,
                  store_name=store_name,
                  alert_time=alert_time,
                  customer_name=customer_name,
                  source=source)
        if retry: # 这是token无效重试的场景
            cls.clear_token()
        try:
            resp = cls._send_messages(**kw)
        except TokenExpired: 
            if retry:  
                logger.error("已经重试过依然抛出了token问题。")
            else:
                resp = cls.send_messages(**kw, retry=True)
        except Exception as e:
            resp.error(e)
        finally:
            return resp



if __name__ == '__main__':
    pass